//
// Created by Yun on 2025/2/13.
//

#include "bsp_flash.h"

/* Flash配置初始化 */
static Bsp_Flash_Cfg_TypeDef stFlashCfg ={
    .u32FlashBaseCfg        = 0x08000000,
    .u32FlashPageSizeCfg    = 2 * 1024,
    .u32FlashSizeCfg        = 256 * 1024
};

/* Flash配置指针 */
static Bsp_Flash_Cfg_TypeDef* pstFlashCfg = &stFlashCfg;

/*!
 * @brief  Flash        获取页号
 * @param u32Addr       flash地址
 * @return  页号
 */
static uint32_t Bsp_Flash_Get_Page(uint32_t u32Addr)
{
    if( u32Addr < pstFlashCfg->u32FlashBaseCfg ||
        u32Addr >= (pstFlashCfg->u32FlashBaseCfg + pstFlashCfg->u32FlashSizeCfg))
        return 0xFFFFFFFF;

    return (u32Addr - pstFlashCfg->u32FlashBaseCfg) / pstFlashCfg->u32FlashPageSizeCfg;
}

/*!
 * @brief  Flash        地址检查
 * @param u32Addr       flash地址
 * @param u32Len        长度
 * @param u8Mode        数据模式
 * @return BSP_OK 成功 BSP_ERROR 失败
 */
static uint8_t Bsp_Flash_Address_Check(uint32_t u32Addr,uint32_t u32Len,uint8_t u8Mode)
{
    // 参数有效性检查
    if( u32Addr < pstFlashCfg->u32FlashBaseCfg ||
        (u32Addr + u32Len) > (pstFlashCfg->u32FlashBaseCfg + pstFlashCfg->u32FlashSizeCfg))
        return BSP_ERROR;

    // 对齐检查
    switch(u8Mode) {
        case BSP_FLASH_DATA_U8:
            break;
        case BSP_FLASH_DATA_U16:
            if((u32Addr % 2) != 0) return BSP_ERROR;
            break;
        case BSP_FLASH_DATA_U32:
            if((u32Addr % 4) != 0) return BSP_ERROR;
            break;
        default:
            return BSP_ERROR;
    }

    return BSP_OK;
}

uint8_t Bsp_Flash_Init(uint32_t u32FlashBase, uint32_t u32FlashPageSize, uint32_t u32FlashSize)
{
    pstFlashCfg->u32FlashBaseCfg         = u32FlashBase;
    pstFlashCfg->u32FlashPageSizeCfg     = u32FlashPageSize;
    pstFlashCfg->u32FlashSizeCfg         = u32FlashSize;
    return BSP_OK;
}

uint8_t Bsp_Flash_Erase(uint32_t u32Addr, uint32_t u32Len) {

    uint32_t u32FirstPage = Bsp_Flash_Get_Page(u32Addr);
    uint32_t u32LastPage  = Bsp_Flash_Get_Page(u32Addr + u32Len - 1);

    if(u32FirstPage == 0xFFFFFFFF || u32LastPage == 0xFFFFFFFF) return BSP_ERROR;

    // 解锁流程增强
    if(HAL_FLASH_Unlock() != HAL_OK) {
        return BSP_ERROR;
    }

    // 强制清除所有中断标志
    __disable_irq();
    SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk; // 清除SysTick中断
    NVIC_ClearPendingIRQ(NonMaskableInt_IRQn);

    FLASH_EraseInitTypeDef erase = {
        .TypeErase = FLASH_TYPEERASE_PAGES,
        .PageAddress = pstFlashCfg->u32FlashBaseCfg + u32FirstPage * pstFlashCfg->u32FlashPageSizeCfg,
        .NbPages = u32LastPage - u32FirstPage + 1
    };

    uint32_t page_error = 0;
    HAL_StatusTypeDef status;

    // 增加超时机制
    uint32_t timeout = 1000; // 1秒超时
    status = HAL_FLASHEx_Erase(&erase, &page_error);
    while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) && timeout--) {
        // 等待操作完成
    }

    HAL_FLASH_Lock();
    __enable_irq();

    if(status != HAL_OK || timeout == 0) {
        return BSP_ERROR;
    }
    return BSP_OK;
}

uint8_t Bsp_Flash_Read(uint32_t u32Addr, void* pBuffer, uint32_t u32Len, uint32_t u8Mode)
{
    Bsp_Flash_Address_Check(u32Addr, u32Len, u8Mode);

    // 根据模式进行不同处理
    switch(u8Mode) {
        case BSP_FLASH_DATA_U8: {
            // 直接字节访问
            memcpy((uint8_t*)pBuffer, (uint8_t*)u32Addr, u32Len * sizeof(uint8_t));
            break;
        }
        case BSP_FLASH_DATA_U16: {
            memcpy((uint16_t*)pBuffer, (const uint16_t*)u32Addr, u32Len * sizeof(uint16_t));
            break;
        }
        case BSP_FLASH_DATA_U32: {
            memcpy((uint32_t*)pBuffer, (const uint32_t*)u32Addr, u32Len * sizeof(uint32_t));
            break;
        }
        default:
            return BSP_ERROR;
    }
    return  BSP_OK;
}

uint8_t Bsp_Flash_Write(uint32_t u32Addr, void* pBuffer, uint32_t u32Len, uint32_t u8Mode)
{
    Bsp_Flash_Address_Check(u32Addr, u32Len, u8Mode);
    
    // 自动擦除
    if(Bsp_Flash_Erase(u32Addr, u32Len) != BSP_OK) return BSP_ERROR;

    HAL_FLASH_Unlock();
    __disable_irq();

    switch(u8Mode) {
        case BSP_FLASH_DATA_U8: {
            uint8_t  *pu8Buffer  = (uint8_t*)pBuffer;
            // 字节模式：两个字节组合为半字
            for(uint32_t i = 0; i < u32Len; i += 2) {
                uint16_t val = (pu8Buffer[i+1] << 8) | pu8Buffer[i];
                if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,
                                     u32Addr + i, val) != HAL_OK) {
                    HAL_FLASH_Lock();
                    __enable_irq();
                    return BSP_ERROR;
                }
            }
            break;
        }
        case BSP_FLASH_DATA_U16: {
            uint16_t *pu16Buffer = (uint16_t*)pBuffer;
            // 半字模式：直接写入
            for(uint32_t i = 0; i < u32Len; i++) {
                if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,
                                     u32Addr + i*2, pu16Buffer[i]) != HAL_OK) {
                    HAL_FLASH_Lock();
                    __enable_irq();
                    return BSP_ERROR;
                }
            }
            break;
        }
        case BSP_FLASH_DATA_U32: {
            uint32_t *pu32Buffer = (uint32_t*)pBuffer;
            for(uint32_t i = 0; i < u32Len; i++) {
                if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
                                     u32Addr + i*4, pu32Buffer[i]) != HAL_OK) {
                    HAL_FLASH_Lock();
                    __enable_irq();
                    return BSP_ERROR;
                }
            }
            break;
        }
        default:
            return BSP_ERROR;
    }

    __enable_irq();
    HAL_FLASH_Lock();

    return BSP_OK;
}

Flash_Interface_TypeDef stBspFlashInterface = {
    .Init     = Bsp_Flash_Init,
    .Erase    = Bsp_Flash_Erase,
    .Write    = Bsp_Flash_Write,
    .Read     = Bsp_Flash_Read
};
